﻿using K3Cloud.WebApi.Core.IoC.Attributes;
using K3Cloud.WebApi.Core.IoC.Cache;
using K3Cloud.WebApi.Core.IoC.DataEntity;
using K3Cloud.WebApi.Core.IoC.DataEntity.PresetEntity;
using K3Cloud.WebApi.Core.IoC.Extensions;
using Newtonsoft.Json;
using SQLBuilder.Enums;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using K3Ioc = K3Cloud.WebApi.Core.IoC.K3IOCServiceCollectionExtensions;

namespace K3Cloud.WebApi.Core.IoC.K3Client;

public sealed partial class K3CloudApiClient(K3Config config)
{
    private readonly K3Config k3Config = config;

    /// <summary>
    /// 切换用户
    /// </summary>
    public K3CloudApiClient User(string userName, string? password = null)
    {
        if (string.IsNullOrEmpty(userName)) return this;
        k3Config.UserName = userName;
        k3Config.Password = password;
        K3Ioc.CacheService.RemoveAll();
        return this;
    }

    /// <summary>
    /// 用户验证
    /// </summary>
    public async Task<bool> ValidateUserAsync(CancellationToken cancellation = default)
    {
        if (!string.IsNullOrEmpty(k3Config.Password)) { return await ValidateUserAsync(k3Config.UserName, k3Config.Password, cancellation); }
        string cacheKey = string.Join("_", "ValidateUser", Process.GetCurrentProcess().StartTime, k3Config.AcctId, k3Config.AppID, k3Config.AppSecret, k3Config.UserName);
        if (K3Ioc.CacheService.ContainsKey<bool>(cacheKey)) { return K3Ioc.CacheService.Get<bool>(cacheKey); }
        object[] Parameters = [k3Config.AcctId, k3Config.UserName, k3Config.AppID, k3Config.AppSecret, k3Config.LCID];
        string htmlContent = await K3Ioc.HttpClient.PostAsync(k3Config.ServerHost,
                                    "/Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginByAppSecret.common.kdsvc",
                                    JsonConvert.SerializeObject(Parameters),
                                    cancellation);
        try
        {
            LoginResult? result = JsonConvert.DeserializeObject<LoginResult?>(htmlContent);
            if (result != null && result.LoginResultType != LoginResultType.Success)
            {
                throw new K3ApiException(result.Message);
            }
            K3Ioc.LoginResult = result;
            K3Ioc.CacheService.Add(cacheKey, result?.LoginResultType == LoginResultType.Success, k3Config.ConnectionValidTime * 60);
            return result?.LoginResultType == LoginResultType.Success;
        }
        catch (Exception ex)
        {
            throw new K3ApiException(ex.Message);
        }
    }
    /// <summary>
    /// 用户验证
    /// </summary>
    public async Task<bool> ValidateUserAsync(string user, string? pass, CancellationToken cancellation = default)
    {
        if (pass == null) return false;
        object[] Parameters = [k3Config.AcctId, user, pass, k3Config.LCID];
        string htmlContent = await K3Ioc.HttpClient.PostAsync(k3Config.ServerHost,
                            "/Kingdee.BOS.WebApi.ServicesStub.AuthService.ValidateUser.common.kdsvc",
                            JsonConvert.SerializeObject(Parameters),
                            cancellation);
        LoginResult? result = JsonConvert.DeserializeObject<LoginResult>(htmlContent);
        K3Ioc.LoginResult = result;
        return result?.LoginResultType == LoginResultType.Success;
    }

    #region 表单查询
    /// <summary>
    /// 查询表单
    /// </summary>
    /// <typeparam name="T">表单class</typeparam>
    /// <param name="field">字段(多字段用,隔开)</param>
    /// <param name="filter">筛选表达式</param>
    /// <param name="order">排序规则(asc或desc)</param>
    /// <param name="topRowCount">返回总行数，整型（非必录）</param>
    /// <param name="startRow">开始行索引，整型（非必录）</param>
    /// <param name="limit">最大行数，整型，不能超过2000（非必录）</param>
    /// <returns></returns>
    public async Task<List<T>> NativeExecuteBillQueryAsync<T>(string? field = null, string filter = "", string order = "", int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default)
    {
        string formId = typeof(T).GetAlias();
        List<T> list = [];
        PropertyInfo[] fieldProperties = typeof(T).GetProperties().Where(t => t.GetCustomAttributes(typeof(ignoreAttribute), true).Length == 0).ToArray();
        if (field != null)
        {
            string[] fields = field.Split(',');
            PropertyInfo[] p = new PropertyInfo[fields.Length];
            for (int i = 0; i < fields.Length; i++)
            {   //有别名则找到别名属性
                p[i] = fieldProperties.Where(t => t.GetCustomAttribute<AliasAttribute>() == null ?
                        t.Name.Equals(fields[i], StringComparison.OrdinalIgnoreCase) :
                        t.GetCustomAttribute<AliasAttribute>()!.Name.Equals(fields[i], StringComparison.OrdinalIgnoreCase)).First();
                if (p[i] == null)
                {   //约定__(双下划线互换)
                    p[i] = fieldProperties.Where(t => t.Name.Equals(fields[i].Replace(".", "__"), StringComparison.OrdinalIgnoreCase)).First();
                }
            }
            fieldProperties = p;
        }
        else
        {   //约定__(双下划线互换)
            field = string.Join(",", fieldProperties.Select(x => x.GetCustomAttribute<AliasAttribute>()?.Name ?? x.Name).ToArray()).Replace("__", ".");
        }
        string? rest = await NativeExecuteBillQueryAsync(formId, field, filter, order, topRowCount, startRow, limit, cancellation);
        if (rest == null) { return list; }
        List<List<object>>? data = JsonConvert.DeserializeObject<List<List<object>>>(rest);
        if (data == null) { return list; }
        if (data.Count == 0) { return list; }
        for (int i = 0; i < data.Count; i++)
        {
            var item = Activator.CreateInstance<T>();
            if (item == null) { continue; }
            for (int j = 0; j < fieldProperties.Length; j++)
            {
                if (data[i][j] == null) { continue; }
                object? propertyValue = ConvertNullableType(data[i][j], item.GetType().GetProperty(fieldProperties[j].Name)?.PropertyType);
                SetPropertyValue(item, fieldProperties[j].Name, propertyValue);
            }
            list.Add(item);
        }
        return list;
    }
    /// <summary>
    /// 查询表单
    /// </summary>
    /// <param name="formId">表单Id</param>
    /// <param name="field">字段(多字段用,隔开)</param>
    /// <param name="filter">筛选表达式</param>
    /// <param name="order">排序规则(asc或desc)</param>
    /// <param name="topRowCount">返回总行数，整型（非必录）</param>
    /// <param name="startRow">开始行索引，整型（非必录）</param>
    /// <param name="limit">最大行数，整型，不能超过2000（非必录）</param>
    public async Task<string?> NativeExecuteBillQueryAsync(string formId, string field, string filter = "", string order = "", int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default)
    {
        QueryParam obj = new()
        {
            FormId = formId,
            FieldKeys = field,
            FilterString = filter,
            OrderString = order,
            TopRowCount = topRowCount,
            StartRow = startRow,
            Limit = limit
        };
        return await NativeExecuteBillQueryAsync(obj, cancellation);
    }
    public async Task<string?> NativeExecuteBillQueryAsync(QueryParam data, CancellationToken cancellationToken = default)
    {
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery", data, cancellationToken);
        return rest == null ? null : rest.Contains("MsgCode") || rest.Contains("_Bracket") ? throw new K3ApiException(rest) : rest;
    }
    /// <summary>
    /// 表单查询(json)
    /// </summary>
    /// <param name="field"> 字段可以使用别名 如：FMaterialId.FNumber AS FNumber </param>
    public async Task<string?> NativeBillQueryAsync(string formId, string field, string filter = "", string order = "", int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default)
    {
        QueryParam obj = new()
        {
            FormId = formId,
            FieldKeys = field,
            FilterString = filter,
            OrderString = order,
            TopRowCount = topRowCount,
            StartRow = startRow,
            Limit = limit
        };
        return await NativeBillQueryAsync(obj, cancellation);
    }
    public async Task<string?> NativeBillQueryAsync(QueryParam query, CancellationToken cancellation = default)
    {
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.BillQuery", query, cancellation);
        return rest == null ? null : rest.Contains("MsgCode") || rest.Contains("_Bracket") ? throw new K3ApiException(rest) : rest;
    }
    /// <summary>
    /// 原生态表单查询
    /// </summary>
    public async Task<string?> NativeExecuteBillQueryAsync(string formId, string field, K3FilterString[] filter, string order = "", int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default)
    {
        var obj = new
        {
            FormId = formId,
            FieldKeys = field,
            FilterString = filter,
            OrderString = order,
            TopRowCount = topRowCount,
            StartRow = startRow,
            Limit = limit
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery", obj, cancellation);
        return rest == null ? null : rest.Contains("MsgCode") || rest.Contains("_Bracket") ? throw new K3ApiException(rest) : rest;
    }
    /// <summary>
    /// 查询表单
    /// </summary>
    public async Task<List<T>> ExecuteBillQueryAsync<T>(string? filterString = null, string? orderString = null, int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default) where T : class
    {
        return await NativeExecuteBillQueryAsync<T>(null, filterString ?? "", orderString ?? "", topRowCount, startRow, limit, cancellation);
    }
    /// <summary>
    /// 查询表单
    /// </summary>
    public async Task<List<T>> ExecuteBillQueryAsync<T>(Expression<Func<T, bool>> filterExpression, string? orderString = null, int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default) where T : class
    {
        string filterString = ExpressionBuilder.GetFilterString(filterExpression);
        return await ExecuteBillQueryAsync<T>(filterString, orderString, topRowCount, startRow, limit, cancellation);
    }
    /// <summary>
    /// 查询表单
    /// </summary>
    public async Task<List<T>> ExecuteBillQueryAsync<T>(Expression<Func<T, bool>>? filterExpression, Expression<Func<T, object>>? orderExpression, OrderType[]? orders = default, int topRowCount = 0, int startRow = 0, int limit = 0, CancellationToken cancellation = default) where T : class
    {
        string filterString = ExpressionBuilder.GetFilterString(filterExpression);
        string orderString = ExpressionBuilder.GetOrderString(orderExpression, orders);
        return await ExecuteBillQueryAsync<T>(filterString, orderString, topRowCount, startRow, limit, cancellation);
    }
    /// <summary>
    /// 查询表单<typeparamref name="T"/> 的链式操作
    /// </summary>
    /// <typeparam name="T">表单类</typeparam>
    public IK3Queryable<T> Queryable<T>() where T : class
    {
        return new K3Queryable<T>();
    }
    /// <summary>
    /// 查询表单<typeparamref name="T"/> 的链式操作
    /// </summary>
    public IK3Queryable<T> Queryable<T>(Expression<Func<T, bool>>? whereExpression) where T : class
    {
        return new K3Queryable<T>(whereExpression);
    }
    /// <summary>
    /// WebAPI查询记录总数
    /// </summary>
    /// <param name="countField">计数字段（有分录明细时不要设置成单据头字段）</param>
    public async Task<int> GetTotalCountAsync<T>(Expression<Func<T, bool>>? filterExpression, string countField, CancellationToken cancellation = default) where T : class
    {
        string formId = typeof(T).GetAlias();
        string filterString = ExpressionBuilder.GetFilterString(filterExpression);
        return await GetTotalCountAsync(formId, filterString, countField, cancellation);
    }
    public async Task<int> GetTotalCountAsync(string formId, string filterString, string countField, CancellationToken cancellation = default)
    {
        if (string.IsNullOrWhiteSpace(countField)) return 0;
        string filter = countField + " IS NOT NULL";
        if (!string.IsNullOrEmpty(filterString))
        {
            filter = filterString + " AND " + filter;
        }
        return await GetTotalCountAsync(formId, filter, cancellation);
    }
    public async Task<int> GetTotalCountAsync(string formId, string filterString, CancellationToken cancellation = default)
    {
        string? rest = await NativeExecuteBillQueryAsync(formId, "count(1) AS BillCount", filterString, "", 0, 0, 0, cancellation);
        if (rest == null)
        {
            return 0;
        }

        List<List<object>>? res = JsonConvert.DeserializeObject<List<List<object>>?>(rest);
        return res == null ? 0 : int.Parse(res[0][0].ToString()!);
    }
    /// <summary>
    /// WebAPI查询记录 合计
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="filterExpression">筛选条件</param>
    /// <param name="sumFiled">合计字段</param>
    /// <returns></returns>
    public async Task<Dictionary<string, decimal>?> GetSumAsync<T>(Expression<Func<T, bool>>? filterExpression, CancellationToken cancellation = default, params string[] sumFiled) where T : class
    {
        if (sumFiled.Length == 0) { return null; }
        Dictionary<string, decimal> dic = [];
        List<string> fildStr = [];
        Expression<Func<T, bool>>? tmp = default;
        foreach (string item in sumFiled)
        {
            tmp = tmp.AddFilter(item, "<>", 0, EnumAndOr.Or);
            fildStr.Add($"sum({item}) AS {item}");
        }
        string msql = ExpressionBuilder.GetFilterString(tmp);
        string ksql = ExpressionBuilder.GetFilterString(filterExpression);
        string filter = string.IsNullOrEmpty(ksql) ? msql : $"({ksql}) AND ({msql})";
        string? rest = await NativeExecuteBillQueryAsync(typeof(T).GetAlias(), string.Join(",", fildStr), filter, "", 0, 0, 0, cancellation);
        if (rest == null)
        {
            return dic;
        }

        rest = rest.Replace("null", "0");
        List<List<decimal>>? data = JsonConvert.DeserializeObject<List<List<decimal>>>(rest);
        for (int i = 0; i < sumFiled.Length; i++)
        {
            if (data == null)
            {
                dic.Add(sumFiled[i], 0);
            }
            else
            {
                dic.Add(sumFiled[i], data[0][i]);
            }
        }
        return dic;
    }
    public async Task<Dictionary<string, decimal>?> GetSumAsync(string FormId, string FilterString, params string[] sumFiled)
    {
        return await GetSumAsync(FormId, FilterString, default, sumFiled);
    }

    public async Task<Dictionary<string, decimal>?> GetSumAsync(string FormId, string FilterString, CancellationToken cancellation = default, params string[] sumFiled)
    {
        if (sumFiled.Length == 0) { return null; }
        Dictionary<string, decimal> dic = [];
        List<string> fildStr = [];
        List<string> fildStr2 = [];
        foreach (string item in sumFiled)
        {
            fildStr.Add($"sum({item}) AS {item}");
            fildStr2.Add($"{item}<>0");
        }
        string msql = string.Join(" OR ", fildStr2);
        string filter = string.IsNullOrEmpty(FilterString) ? msql : FilterString + $" AND ({msql})";
        string? rest = await NativeExecuteBillQueryAsync(FormId, string.Join(",", fildStr), filter, "", 0, 0, 0, cancellation);
        if (rest == null)
        {
            return dic;
        }

        rest = rest.Replace("null", "0");
        List<List<decimal>>? data = JsonConvert.DeserializeObject<List<List<decimal>>>(rest);
        for (int i = 0; i < sumFiled.Length; i++)
        {
            if (data == null)
            {
                dic.Add(sumFiled[i], 0);
            }
            else
            {
                dic.Add(sumFiled[i], data[0][i]);
            }
        }
        return dic;
    }

    /// <summary>
    /// 即时库存查询
    /// </summary>
    /// <returns></returns>
    public async Task<ResponseModel?> GetInventoryDataAsync(InventoryParamModel paramData, CancellationToken cancellationToken = default)
    {
        string? rest = await ExecuteAsync("Kingdee.K3.SCM.WebApi.ServicesStub.InventoryQueryService.GetInventoryData", JsonConvert.SerializeObject(new[] { paramData }), true, cancellationToken);
        return rest == null ? null : JsonConvert.DeserializeObject<ResponseModel>(rest);
    }
    #endregion

    #region 表单保存
    /// <summary>
    /// 表单保存
    /// </summary>
    /// <param name="bill">表单</param>
    /// <param name="IsAutoSubmitAndAudit">自动提交审核</param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> SaveAsync<T>(K3SaveParam<T> bill, bool IsAutoSubmitAndAudit = false, CancellationToken cancellationToken = default) where T : class
    {
        string FormId = bill.GetFormId();
        string? response = await SaveAsync(FormId, bill, cancellationToken);
        if (response == null)
        {
            return null;
        }

        K3ApiResult<K3SaveResult>? saveResult = JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(response);
        if (saveResult == null)
        {
            return null;
        }

        if (IsAutoSubmitAndAudit)
        {
            if (saveResult.Result.ResponseStatus.IsSuccess)
            {
                string pkId = saveResult.Result.ResponseStatus.SuccessEntitys[0].Id;
                K3ApiResult<K3SaveResult>? submitResult = await SubmitAsync(FormId, cancellationToken, pkId);
                if (submitResult == null)
                {
                    return null;
                }

                if (submitResult.Result.ResponseStatus.IsSuccess)
                {
                    K3ApiResult<K3SaveResult>? auditResult = await AuditAsync(FormId, cancellationToken, pkId);
                    return auditResult;
                }
                return submitResult;
            }
        }
        return saveResult;
    }
    public async Task<string?> SaveAsync(string formid, object obj, CancellationToken cancellationToken = default)
    {
        return await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save", formid, obj, cancellationToken);
    }
    /// <summary>
    /// 表单保存(复杂的更新操作,需要手工拼接json时使用)
    /// </summary>
    public async Task<string?> SaveAsync(string content, CancellationToken cancellationToken = default)
    {
        return await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Save", content, cancellationToken);
    }
    #endregion
    public async Task<K3ApiResult<K3SaveResult>?> SubmitAsync(string FormId, params object[] FId)
    {
        return await SubmitAsync(FormId, default, FId);
    }
    /// <summary>
    /// 表单提交
    /// </summary>
    /// <param name="FormId"></param>
    /// <param name="FId"></param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> SubmitAsync(string FormId, CancellationToken cancellation = default, params object[] FId)
    {
        var bill = new
        {
            CreateOrgId = 0,
            Numbers = Array.Empty<string>(),
            Ids = string.Join(",", FId),
            SelectedPostId = 0,
            NetworkCtrl = "",
            IgnoreInterationFlag = ""
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Submit", FormId, bill, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>>(rest);
    }
    public async Task<K3ApiResult<K3SaveResult>?> AuditAsync(string FormId, params object[] FId)
    {
        return await AuditAsync(FormId, default, FId);
    }
    /// <summary>
    /// 表单审核
    /// </summary>
    /// <param name="FormId"></param>
    /// <param name="FId"></param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> AuditAsync(string FormId, CancellationToken cancellation = default, params object[] FId)
    {
        var bill = new
        {
            CreateOrgId = 0,
            Numbers = Array.Empty<string>(),
            Ids = string.Join(",", FId),
            InterationFlags = "",
            NetworkCtrl = "",
            IsVerifyProcInst = "",
            IgnoreInterationFlag = ""
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Audit", FormId, bill, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(rest);
    }
    /// <summary>
    /// 工作流审批
    /// </summary>
    public async Task<K3ApiResult<K3SaveResult>?> WorkflowAuditAsync(WorkflowParam data, CancellationToken cancellation = default)
    {
        string? result = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.WorkflowAudit", data, cancellation);
        return result == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(result);
    }
    public async Task<K3ApiResult<K3SaveResult>?> CancelAssign(string FormId, params int[] FId)
    {
        return await CancelAssign(FormId, default, FId);
    }
    /// <summary>
    /// 撤销服务接口
    /// </summary>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> CancelAssign(string FormId, CancellationToken cancellation = default, params int[] FId)
    {
        var bill = new
        {
            CreateOrgId = 0,
            Numbers = Array.Empty<string>(),
            Ids = string.Join(",", FId),
            NetworkCtrl = ""
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.CancelAssign", FormId, bill, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(rest);
    }
    public async Task<K3ApiResult<K3SaveResult>?> UnAuditAsync(string FormId, params int[] FId)
    {
        return await UnAuditAsync(FormId, default, FId);
    }
    /// <summary>
    /// 表单撤销提交或者反审核
    /// </summary>
    /// <param name="FormId"></param>
    /// <param name="FId"></param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> UnAuditAsync(string FormId, CancellationToken cancellation = default, params int[] FId)
    {
        var bill = new
        {
            CreateOrgId = 0,
            Numbers = Array.Empty<string>(),
            Ids = string.Join(",", FId),
            InterationFlags = "",
            NetworkCtrl = "",
            IsVerifyProcInst = ""
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.UnAudit", FormId, bill, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(rest);
    }
    public async Task<K3ApiResult<K3SaveResult>?> DeleteAsync(string FormId, params int[] FId)
    {
        return await DeleteAsync(FormId, default, FId);
    }

    /// <summary>
    /// 表单删除
    /// </summary>
    /// <param name="FormId"></param>
    /// <param name="FId"></param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> DeleteAsync(string FormId, CancellationToken cancellation = default, params int[] FId)
    {
        var bill = new
        {
            CreateOrgId = 0,
            Numbers = Array.Empty<string>(),
            Ids = string.Join(",", FId),
            NetworkCtrl = ""
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Delete", FormId, bill, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>>(rest);
    }
    /// <summary>
    /// 下推单据
    /// </summary>
    /// <param name="FormId">表单ID</param>
    /// <param name="entryIds">分录内码,多条分录用逗号分隔</param>
    /// <param name="ruleId">单据转换内码</param>
    /// <param name="customParams">自定义参数</param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> PushAsync(string FormId, string entryIds, string ruleId, object? customParams = null, CancellationToken cancellation = default)
    {
        var data = new
        {
            Ids = "",
            Numbers = Array.Empty<string>(),
            EntryIds = entryIds,
            RuleId = ruleId,
            TargetBillTypeId = "",
            TargetOrgId = 0,
            TargetFormId = "",
            IsEnableDefaultRule = "false",
            IsDraftWhenSaveFail = "false",
            CustomParams = customParams
        };
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.Push", FormId, data, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(rest);
    }
    /// <summary>
    /// 操作接口
    /// </summary>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> ExcuteOperationAsync(string formid, string opNumber, object data, CancellationToken cancellationToken = default)
    {
        object[] obj = [formid, opNumber, data];
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExcuteOperation", JsonConvert.SerializeObject(obj), cancellationToken);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(rest);
    }

    #region 生产订单操作接口
    /// <summary>
    /// 生产订单强制结案
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3SaveResult>?> ForceCloseAsync(ExcuteOperationData data, CancellationToken cancellation = default)
    {
        return await ExcuteOperationAsync("PRD_MO", "ForceClose", data, cancellation);
    }
    /// <summary>
    /// 生产订单反执行至完工
    /// </summary>
    public async Task<K3ApiResult<K3SaveResult>?> UndoToFinishAsync(ExcuteOperationData data, CancellationToken cancellation = default)
    {
        return await ExcuteOperationAsync("PRD_MO", "UndoToFinish", data, cancellation);
    }
    #endregion
    public async Task<K3ApiResult<K3SaveResult>?> SendMessageAsync(Expression<Func<SEC_User, bool>> expression, string title, string content, string? FormId = null, string? FId = null, CancellationToken cancellation = default)
    {
        List<SEC_User> user = await ExecuteBillQueryAsync(expression, "", 0, 0, 0, cancellation);
        string userIds = string.Join(",", user.Select(t => t.FUserId).ToArray());
        List<K3MessageModel> msgList =
        [
            new K3MessageModel
            {
                FTitle = title,
                FContent = content,
                FReceivers = userIds,
                FObjectTypeId = FormId,
                FKeyValue = FId
            }
        ];
        K3ApiResult<K3SaveResult>? rest = await SendMessageAsync(msgList, cancellation);
        return rest;
    }

    public async Task<K3ApiResult<K3SaveResult>?> SendMessageAsync(List<K3MessageModel> models, CancellationToken cancellation = default)
    {
        K3CloudMessage data = new(models);
        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.SendMsg", data, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3SaveResult>?>(rest);
    }
    /// <summary>
    /// 元数据查询(默认取缓存)
    /// </summary>
    public async Task<K3ApiResult<K3BusinessInfoResult>?> GetBusinessInfoAsync(string FormId, bool cache = true, int cacheDurationInSeconds = 20 * 60, CancellationToken cancellation = default)
    {
        string key = nameof(GetBusinessInfoAsync) + FormId;
        if (K3Ioc.CacheService.ContainsKey<K3ApiResult<K3BusinessInfoResult>?>(key)) { return K3Ioc.CacheService.Get<K3ApiResult<K3BusinessInfoResult>?>(key); }
        K3ApiResult<K3BusinessInfoResult>? rest = await QueryBusinessInfoAsync(FormId, cancellation);
        K3Ioc.CacheService.Add(key, rest, cacheDurationInSeconds);
        return rest;
    }
    /// <summary>
    /// 元数据查询
    /// </summary>
    /// <param name="FormId">业务对象表单Id（必录）</param>
    /// <returns></returns>
    public async Task<K3ApiResult<K3BusinessInfoResult>?> QueryBusinessInfoAsync(string FormId, CancellationToken cancellation = default)
    {
        if (string.IsNullOrEmpty(FormId))
        {
            return null;
        }

        string? rest = await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.QueryBusinessInfo", new { FormId }, cancellation);
        return rest == null ? null : JsonConvert.DeserializeObject<K3ApiResult<K3BusinessInfoResult>>(rest);
    }

    /// <summary>
    /// 元数据查询
    /// </summary>
    public async Task<K3ApiResult<K3BusinessInfoResult>?> QueryBusinessInfoAsync<T>(CancellationToken cancellation = default)
    {
        string FormId = typeof(T).GetAlias();
        return await QueryBusinessInfoAsync(FormId, cancellation);
    }
    public async Task<List<DataCenter>?> GetDataCentersAsync(CancellationToken cancellationToken = default)
    {
        var httpContent = await K3Ioc.HttpClient.GetAsync(k3Config.ServerHost,
                            "/Kingdee.BOS.ServiceFacade.ServicesStub.Account.AccountService.GetDataCenterList.common.kdsvc",
                            cancellationToken);
        return JsonConvert.DeserializeObject<List<DataCenter>?>(httpContent);
    }

    /// <summary>
    /// 请求自定义接口
    /// 如：获取汇率体系元数据
    /// var pram =  new { FormId = "BD_Rate" };
    /// var ret = await K3Scoped.Client.ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.QueryBusinessInfo", pram);
    /// </summary>
    /// <param name="servicename">服务名</param>
    /// <param name="data">参数</param>
    /// <returns></returns>
    public async Task<string?> ExecuteAsync(string servicename, object? data, CancellationToken cancellation = default)
    {
        return await ExecuteAsync(servicename, data == null ? null : JsonConvert.SerializeObject(new object[1] { data }), cancellation);
    }

    public async Task<string?> ExecuteAsync(string servicename, string formid, object? data, CancellationToken cancellation = default)
    {
        return await ExecuteAsync(servicename, JsonConvert.SerializeObject(new object[2] { formid, data ?? "" }), cancellation);
    }

    public async Task<string?> ExecuteAsync(string servicename, string? parameters, CancellationToken cancellation = default)
    {
        bool validate;
        CancellationTokenSource timeout = new();
        timeout.CancelAfter(TimeSpan.FromMinutes(k3Config.ConnectionValidTime) == TimeSpan.Zero ? TimeSpan.FromSeconds(30) : TimeSpan.FromMinutes(k3Config.ConnectionValidTime));
        CancellationToken timeoutToken = timeout.Token;
        using CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(cancellation, timeoutToken);
        validate = k3Config.UserName != null && k3Config.Password != null
            ? await ValidateUserAsync(k3Config.UserName, k3Config.Password, cts.Token)
            : await ValidateUserAsync(cts.Token);
        if (validate)
        {
#if DEBUG
            Debug.WriteLine($"请求接口：{servicename}.common.kdsvc");
            Debug.WriteLine($"请求参数：{parameters}");
#endif
            return await K3Ioc.HttpClient.PostAsync(k3Config.ServerHost,
                        $"/{servicename}.common.kdsvc",
                        parameters,
                        cts.Token);
        }
        return null;
    }
    /// <summary>
    /// 下载文件服务器附件
    /// </summary>
    public async Task<string?> Download(string _fileId, CancellationToken cancellation = default)
    {
        var data = new
        {
            FileId = _fileId,
            StartIndex = 0
        };
        return await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.AttachmentDownLoad", data, cancellation);
    }

    /// <summary>
    /// 附件上传
    /// </summary>
    public async Task<string?> UploadToBill(string FileName, string FormId, bool IsLast, string InterId, string BillNO, string SendByte, string? AliasFileName, CancellationToken cancellationToken = default)
    {
        var data = new
        {
            FileName,
            FormId,
            IsLast,
            InterId,
            BillNO,
            AliasFileName,
            SendByte
        };
        return await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.AttachmentUpLoad", data, cancellationToken);
    }
    /// <summary>
    /// 附件上传
    /// <a href="https://vip.kingdee.com/article/296577252589190400"/> 
    /// </summary>
    public async Task<string?> UploadToBill(object data, CancellationToken cancellationToken = default)
    {
        return await ExecuteAsync("Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.AttachmentUpLoad", data, cancellationToken);
    }
    #region Cache
    /// <summary>
    /// 释放缓存
    /// </summary>
    public void ReleaseCache()
    {
        K3Ioc.CacheService.RemoveAll();
    }
    /// <summary>
    /// 设置默认缓存
    /// </summary>
    public void DefaultCache()
    {
        K3Ioc.CacheService = new MemoryCacheService();
    }
    #endregion
    #region JSON
    public string ToJson(QueryParam data, JsonSerializerSettings? settings = default)
    {
        return JsonConvert.SerializeObject(data, settings);
    }
    public string ToJson<T>(Expression<Func<T, bool>>? filterExpression, Expression<Func<T, object>>? orderExpression, OrderType[]? orders = default, int topRowCount = 0, int startRow = 0, int limit = 0, JsonSerializerSettings? settings = default) where T : class
    {
        string formId = typeof(T).GetAlias();
        PropertyInfo[] fieldProperties = typeof(T).GetProperties().Where(t => t.GetCustomAttributes(typeof(ignoreAttribute), true).Length == 0).ToArray();
        string? field = string.Join(",", fieldProperties.Select(x => x.GetCustomAttribute<AliasAttribute>()?.Name ?? x.Name).ToArray()).Replace("__", ".");
        string filterString = ExpressionBuilder.GetFilterString(filterExpression);
        string orderString = ExpressionBuilder.GetOrderString(orderExpression, orders);
        QueryParam obj = new()
        {
            FormId = formId,
            FieldKeys = field,
            FilterString = filterString,
            OrderString = orderString,
            TopRowCount = topRowCount,
            StartRow = startRow,
            Limit = limit
        };
        return ToJson(obj, settings);
    }
    #endregion
    /// <summary>
    /// 转换可空类型值
    /// </summary>
    /// <returns></returns>
    private static object? ConvertNullableType(object value, Type? conversionType)
    {
        if (value == null) { return null; }
        if (conversionType == null) { return value; }
        if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        {
            NullableConverter nullableConverter = new(conversionType);
            conversionType = nullableConverter.UnderlyingType;
        }
        else if (conversionType.IsEnum)
        {
            return value;
        }
        try
        {
            return typeof(IList).IsAssignableFrom(conversionType) ? value : Convert.ChangeType(value, conversionType);
        }
        catch
        {
            return conversionType.IsValueType ? Activator.CreateInstance(conversionType) : null;
        }
    }

    /// <summary>
    /// 给属性赋值
    /// </summary>
    /// <param name="objectValue">this</param>
    /// <param name="propertyName">属性名</param>
    /// <param name="value">属性值</param>
    private void SetPropertyValue(object objectValue, string propertyName, object? value)
    {
        if (value == null) return;
        PropertyInfo? propertyInfo = objectValue.GetType().GetProperty(propertyName);
        if (propertyInfo == null) return;
        if (typeof(IList).IsAssignableFrom(propertyInfo.PropertyType))
        {
            if (propertyInfo.PropertyType == typeof(byte[]))
            {
                byte[] byteArray = Convert.FromBase64String((string)value);
                propertyInfo.SetValue(objectValue, byteArray, null);
                return;
            }
            object? newList = Activator.CreateInstance(typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GenericTypeArguments));
            propertyInfo.SetValue(objectValue, newList, null);
            MethodInfo? addMethod = newList?.GetType().GetMethod("Add");
            foreach (object item in (IEnumerable)value)
            {
                _ = addMethod?.Invoke(newList, [item]);
            }
        }
        else if (typeof(Enum).IsAssignableFrom(propertyInfo.PropertyType))
        {
            object enumValue = Enum.Parse(propertyInfo.PropertyType, value.ToString()!);
            propertyInfo.SetValue(objectValue, enumValue);
        }
        else
        {
            propertyInfo.SetValue(objectValue, value, null);
        }

    }
}
